﻿// Decompiled with JetBrains decompiler
// Type: Netick.NetworkDictionarySnapshot`2
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System.Collections;
using System.Collections.Generic;

#nullable disable
namespace Netick;

/// <summary>
/// A snapshot of the state of a <see cref="T:Netick.NetworkDictionary`2" /> collection. Note this must not be used outside the scope of an OnChanged call or a NetworkRender call.
/// </summary>
public struct NetworkDictionarySnapshot<TKey, TValue> : 
  IEnumerable<KeyValuePair<TKey, TValue>>,
  IEnumerable
  where TKey : unmanaged
  where TValue : unmanaged
{
  private unsafe int* Ptr;
  internal int _lengthDoubled;
  private int _entrySizeWords;
  private int _offsetToIterationList;

  public unsafe int Count => *this.Ptr;

  private unsafe NetworkDictionary<TKey, TValue>.Entry* GetEntryElementPointer(int index)
  {
    return (NetworkDictionary<TKey, TValue>.Entry*) (this.Ptr + 1 + index * this._entrySizeWords);
  }

  private unsafe NetworkDictionary<TKey, TValue>.Entry GetEntryElementData(int index)
  {
    return *(NetworkDictionary<TKey, TValue>.Entry*) (this.Ptr + 1 + index * this._entrySizeWords);
  }

  private unsafe int* GetIterationListElementPointer(int index)
  {
    return this.Ptr + this._offsetToIterationList + index;
  }

  private unsafe int GetIterationListElementData(int index)
  {
    return (this.Ptr + this._offsetToIterationList)[index];
  }

  internal unsafe NetworkDictionarySnapshot(int* p, int capacity)
  {
    this.Ptr = p;
    this._lengthDoubled = capacity * 2;
    this._entrySizeWords = NetickUtils.GetWordSize(sizeof (NetworkDictionary<TKey, TValue>.Entry));
    this._offsetToIterationList = 1 + this._lengthDoubled * this._entrySizeWords;
  }

  public TValue this[TKey key]
  {
    get
    {
      TValue obj;
      if (this.TryGetValue(key, out obj))
        return obj;
      throw new KeyNotFoundException();
    }
  }

  public bool TryGetValue(TKey key, out TValue value)
  {
    NetworkDictionary<TKey, TValue>.Entry entry;
    if (this.FindEntry(key, out entry) == -1)
    {
      value = default (TValue);
      return false;
    }
    value = entry.Value;
    return true;
  }

  /// <summary>
  /// Determines whether the dictionary contains the specified key.
  /// </summary>
  /// <param name="key">The key to locate in the dictionary.</param>
  /// <returns>true if the dictionary contains an element with the specified key; otherwise, false.</returns>
  public bool ContainsKey(TKey key)
  {
    return this.FindEntry(key, out NetworkDictionary<TKey, TValue>.Entry _) != -1;
  }

  /// <summary>
  /// Determines whether the dictionary contains a specific value.
  /// </summary>
  /// <param name="value">The value to locate in the dictionary.</param>
  /// <returns>true if the value is found; otherwise, false.</returns>
  public bool ContainsValue(TValue value)
  {
    for (int index = 0; index < this.Count; ++index)
    {
      if (EqualityComparer<TValue>.Default.Equals(this.GetEntryElementData(this.GetIterationListElementData(index)).Value, value))
        return true;
    }
    return false;
  }

  private int FindEntry(TKey key, out NetworkDictionary<TKey, TValue>.Entry value)
  {
    int index = (key.GetHashCode() & int.MaxValue) % this._lengthDoubled;
    int num = index;
    do
    {
      NetworkDictionary<TKey, TValue>.Entry entryElementData = this.GetEntryElementData(index);
      if (entryElementData.IsEverUsed == 0)
      {
        value = new NetworkDictionary<TKey, TValue>.Entry();
        return -1;
      }
      if (!entryElementData.IsEmpty && EqualityComparer<TKey>.Default.Equals(entryElementData.Key, key))
      {
        value = entryElementData;
        return index;
      }
      index = (index + 1) % this._lengthDoubled;
    }
    while (index != num);
    value = new NetworkDictionary<TKey, TValue>.Entry();
    return -1;
  }

  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
  {
    for (int i = 0; i < this.Count; ++i)
    {
      NetworkDictionary<TKey, TValue>.Entry entryElementData = this.GetEntryElementData(this.GetIterationListElementData(i));
      yield return new KeyValuePair<TKey, TValue>(entryElementData.Key, entryElementData.Value);
    }
  }

  IEnumerator IEnumerable.GetEnumerator() => (IEnumerator) this.GetEnumerator();
}
